/* 
    封装axios库：能发送异步ajax请求的函数模块
    优化项：
        1. 统一处理请求异常:
           在外层包一个自己创建的promise对象，在请求出错时，不reject(error)，而是显示错误提示
        2. 异步得到的不是response，而是response.data:
           在请求成功resolve时，resolve(response.data)
*/

/* 
    async 和 await
    1. 作用:
        1) 简化promise对象的作用，不用再使用then()来指定成功/失败的回调函数
        2）以同步编码（没有回调函数了）方式实现异步流程
    2. 哪里写await: 在返回promise的表达式左侧写await，不想要promise，想要promise异步执行成功的value数据
    3. 哪里写async: await所在函数(最近的)定义的左侧
*/


import axios from 'axios'
import { message } from 'antd'
import mem from '@utils/memory'
import {userUrl} from '@config/url'
import { storeToken, storeUser } from './store'

function defaultFailCallback(res) {
    console.log(res)
    // message.error('请求出错:'+ res.message)
}

let instance = axios.create({})



// 请求拦截器
instance.interceptors.request.use(
    // ================ config 对象 ========================
    // adapter: ƒ xhrAdapter(config)
    // data: "{\"username\":\"liuxd\",\"password\":\"123456\"}"
    // headers: {Accept: 'application/json, text/plain, */*', Content-Type: 'application/json'}
    // maxBodyLength: -1
    // maxContentLength: -1
    // method: "post"
    // timeout: 0
    // transformRequest: [ƒ]
    // transformResponse: [ƒ]
    // transitional: {silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false}
    // url: "/api/user/login"
    // validateStatus: ƒ validateStatus(status)
    // xsrfCookieName: "XSRF-TOKEN"
    // xsrfHeaderName: "X-XSRF-TOKEN"
    async config => {
        const {token, expired} = mem.token

        // 判断是否存在token，如果存在的话，则每个http header都加上token
        if (token) {
            // token 过期
            if ( expired <= (new Date().getTime() / 1000) )
            {
                // 过滤刷新token和login接口（防止递归调用）
                if (config.url === userUrl.refresh || config.url === userUrl.login ) {
                    config.headers.Authorization = token
                    return config
                }

                // 此处使用await将axios请求改为同步请求
                await instance.get(userUrl.refresh).then(data => {
                    // console.log("token refresh success:", data)
                    mem.token = data.data.token
                    storeToken.set(mem.token)
                }).catch(res => {
                    // console.log("token refresh failed:", res)
                    mem.token = mem.user = {}
                    storeToken.remove()
                    storeUser.remove()
                    window.location.href = '/user/login'
                })
            }
            config.headers.Authorization = mem.token.token  //请求头加上token, 此处需重新从内存中取，因为token可能已经刷新
        } else {
            // 过滤刷新token和login接口（防止递归调用）
            if (config.url === userUrl.refresh || config.url === userUrl.login ) {
                return config
            }

            console.log("local storage don't have token, redirect to login page")
            mem.token = mem.user = {}
            storeToken.remove()
            storeUser.remove()
            window.location.href = '/user/login'
            // config.cancelToken = new axios.CancelToken(cancel => {
            //     window.__axiosPromiseArr.push({
            //         url: config.url,
            //         cancel
            //     })
            // })
        }

        return config
    },
    err => Promise.reject(err),
)

// 响应拦截器
instance.interceptors.response.use(
    response => response.data,
    error => Promise.reject(error.response)
)

export default function Request(url, data={}, type='POST', callback=defaultFailCallback) {

    return new Promise((resolve, reject) => {
        let promise
        // 1. 执行异步请求
        switch (type) {
            case 'GET':
                promise = instance.get(url, {params:data})
                break;
            case 'POST':
                promise = instance.post(url, data)
                break
            default:
                message.error('unknow request type!!!')
                return;
        }

        promise.then(data => {   // 2. 如果成功了，调用resolve(value)
            resolve(data)
        }).catch( res => {      // 3. 如果失败了，不调用reject(reason)，而是提示异常信息
            // reject(res)
            callback(res)
        })
    })
}